﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Xml;
using VitCode.Castle.Helper;

namespace VitCode.BaseDataPageCreator.Setting
{
    public class LanguageHelper
    {
        private const string TEXT="Text",MEMO="Memo";

        public static string GetConfigKeyValue(string strKey)
        {
            string strVal="";
            if (ConfigurationManager.AppSettings != null)
            {
                strVal = ConfigurationManager.AppSettings[strKey];
                if(strVal == null) strVal = "";
            }
            return strVal;
        }

        public static bool IsOpenLangSetting
        {
            get
            {
                string strVal = GetConfigKeyValue("OpenLanguageSetting");
                if(strVal.ToLower() == "true")
                    return true;
                return false;
            }
        }

        public const string LANUGUAGE_KEY = "LanguageKey",DEFAULT_LANGUAGE_KEY="DefaultLanguageKey";

        public static string LanguageKey
        {
            get
            {
                string strVal = "CN";
                string strDefaultVal = GetConfigKeyValue(DEFAULT_LANGUAGE_KEY);
                if (strDefaultVal.Length > 0) strVal = strDefaultVal;
                string strSettingVal = GetConfigKeyValue(LANUGUAGE_KEY);
                if (strSettingVal.Length > 0) strVal = strSettingVal;
                if(HttpContext.Current.Session != null)
                {
                    object hc = HttpContext.Current.Session[LANUGUAGE_KEY];
                    if(hc!=null)
                    {
                        string strSessionVal = hc.ToString();
                        if (!string.IsNullOrEmpty(strSessionVal)) strVal = strSessionVal;
                    }
                }
                return strVal;
            }
            set
            {
                HttpContext.Current.Session[LANUGUAGE_KEY] = value;
            }
        }

        private static void SetPageCtlMemo(Control c, XmlNode cNode, ObjXmlReader xmlReader)
        {
            if(c!=null&&cNode!=null)
            {
                string strMemo = xmlReader.GetNodeAttributeValue(cNode, MEMO,true);
                PropertyInfo ctlPi = c.GetType().GetProperty(TEXT);
                if(ctlPi!=null && strMemo.Length>0)
                {
                    ctlPi.SetValue(c, strMemo, null);
                }
            }
        }

        public static void SetPageLanguageInfo(Page page)
        {
            SetPageLanguageInfo(page, LanguageKey + ".xml");
        }

        public static void SetPageLanguageInfo(Page page,string languageXmlFileName)
        {
            ObjXmlReader xmlReader = new ObjXmlReader(AppDomain.CurrentDomain.BaseDirectory + "\\Language\\" + languageXmlFileName);
            string strFullName = page.GetType().BaseType.FullName;
            XmlNode node = xmlReader.GetXmlNode("Setting/" + strFullName);
            if(node!=null && node.ChildNodes.Count>0)
            {
                foreach(XmlNode cn in node.ChildNodes)
                {
                    Control ctl = page.FindControl(cn.Name);
                    SetPageCtlMemo(ctl, cn, xmlReader);
                }
            }
        }

        private static void CreateCtlNode(Type objType, XmlNode parentNdoe, XmlDocument xmlDoc, ref StringCollection scFieldIds)
        {
            FieldInfo[] fis = objType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (FieldInfo fi in fis)
            {
                if (fi != null)
                {
                    PropertyInfo pi = fi.FieldType.GetProperty("Text");
                    if (pi == null)
                        pi = fi.FieldType.GetProperty("Value");
                    if (pi != null)
                    {
                        XmlNode xmlEle = SetNode(parentNdoe,fi.Name,xmlDoc);
                        if(xmlEle.Attributes[MEMO]==null)
                            xmlEle.Attributes.Append(xmlDoc.CreateAttribute("Memo"));
                        if (!scFieldIds.Contains(fi.Name))
                            scFieldIds.Add(fi.Name);
                    }
                }
            }
        }

        private static void CreatePageNode(Assembly am, XmlNode parentNode, XmlDocument xmlDoc, Type objType, ref StringCollection scFieldIds)
        {
            Type[] types = am.GetTypes();
            foreach (Type t in types)
            {
                if (t != null && t.BaseType != null && (t.BaseType.Equals(objType)))
                {
                    XmlNode xmlEle = SetNode(parentNode, t.FullName, xmlDoc);
                    parentNode.AppendChild(xmlEle);
                    CreateCtlNode(t, xmlEle, xmlDoc, ref scFieldIds);
                }
            }
        }

        public static XmlNode SetNode(XmlNode parentNode,string nodeName,XmlDocument xmlDoc)
        {
            XmlNode node=null;
            if (!string.IsNullOrEmpty(nodeName)&&parentNode!=null)
            {
                node = parentNode.SelectSingleNode(nodeName);
                if (node==null)
                {
                    node = xmlDoc.CreateElement(nodeName);
                    parentNode.AppendChild(node);
                }
            }
            return node;
        }

        public static void SetLanguageXmlFile(Type innerObjType, string xmlFileFullPath)
        {
            if (innerObjType == null)
                throw new ArgumentException("次版本");
            XmlDocument xmlDoc = new XmlDocument();
            if(!File.Exists(xmlFileFullPath))
            {
                XmlElement root = xmlDoc.CreateElement("Setting");
                xmlDoc.AppendChild(root);
                xmlDoc.Save(xmlFileFullPath);
            }
            xmlDoc.Load(xmlFileFullPath);

            XmlNode settingNode = xmlDoc.SelectSingleNode("Setting");
            XmlNode globalNode = SetNode(settingNode, "Global", xmlDoc);
            XmlNode pageNode = SetNode(settingNode, "Page", xmlDoc);
            XmlNode userControlNode = SetNode(settingNode, "UserControl", xmlDoc);
            
            Assembly am = innerObjType.Assembly;
            StringCollection scFieldIds = new StringCollection();
            CreatePageNode(am, pageNode, xmlDoc, typeof(Page), ref scFieldIds);
            CreatePageNode(am, userControlNode, xmlDoc, typeof(UserControl), ref scFieldIds);
            if(scFieldIds.Count > 0)
            {
                foreach(string str in scFieldIds)
                {
                    XmlNode xmlEle = SetNode(globalNode, str, xmlDoc);
                    if (xmlEle.Attributes[MEMO] == null)
                        xmlEle.Attributes.Append(xmlDoc.CreateAttribute("Memo"));
                }
            }
            xmlDoc.Save(xmlFileFullPath);
        }
        const string PgListKeyWord = "PaginationGrid:PaginationGrid", SCRIPT_KEY="script";
        private static XmlNodeList GetTempXmlNode(string xmlFilePath)
        {

            if (xmlFilePath.EndsWith("ObjEdit.aspx"))
                xmlFilePath = xmlFilePath;
            NameValueCollection htKeyMate = new NameValueCollection();
            htKeyMate.Add("<script", "");
            htKeyMate.Add("<asp:Button", "Text");
            htKeyMate.Add("<asp:Label", "Text");
            htKeyMate.Add("<asp:RegularExpressionValidator", "ErrorMessage");
            htKeyMate.Add("<asp:CompareValidator", "ErrorMessage");
            htKeyMate.Add("<asp:HiddenField", "Value");
            htKeyMate.Add("<asp:RadioButton", "Value");
            htKeyMate.Add("<input", "Value");//<asp:RadioButton
            htKeyMate.Add("<"+PgListKeyWord+" ", "");

            string strTestXmlPath = AppDomain.CurrentDomain.BaseDirectory + "\\text.xml";
            StringCollection sc = new StringCollection();
            StreamReader sr = new StreamReader(xmlFilePath);
            try
            {
                string strInfo = sr.ReadToEnd();
                
                for(int i=0;i<htKeyMate.Count;i++)
                {
                    while (true)
                    {
                        string strKey = htKeyMate.GetKey(i);
                        int startIndex = strInfo.IndexOf(strKey);
                        if (startIndex < 0)
                            break;
                        string tempLastMate = htKeyMate.GetKey(i).Replace("<", "</").Trim() + ">";
                        int tempStartIndex2 = strInfo.IndexOf(htKeyMate.GetKey(i), startIndex + htKeyMate.GetKey(i).Length);
                        int tempEndIndex1 = strInfo.IndexOf("/>", startIndex);
                        int tempEndIndex2 = strInfo.IndexOf(tempLastMate, startIndex);
                        
                        int endIndex = tempEndIndex1;

                        if ((strKey.IndexOf(PgListKeyWord) >-1 || strKey.IndexOf(SCRIPT_KEY) > -1) && tempEndIndex2 > -1 && tempEndIndex2 > startIndex)
                            endIndex = tempEndIndex2;
                        else
                        {
                            if (tempEndIndex2 > -1 && ((tempEndIndex1 == -1 && tempEndIndex2 > startIndex) || (tempEndIndex1 > -1 && tempEndIndex2 < tempEndIndex1)))
                            {
                                endIndex = tempEndIndex2;
                            }
                            else
                                tempLastMate = "/>";
                        }
                        

                        

                        if (endIndex < 0)
                            break;
                        if (tempStartIndex2 > -1 && (tempStartIndex2 < endIndex))
                            break;

                        string xmlVal = strInfo.Substring(startIndex, endIndex + tempLastMate.Length - startIndex);
                        //string headString = xmlVal.Substring(0, et.Key.ToString().Length);
                        //headString = headString.Replace(":", "_-_");
                        //string lastString = xmlVal.Substring(xmlVal.Length - tempLastMate.Length);
                        //lastString = lastString.Replace(":", "_-_");
                        //xmlVal = headString +
                        //         xmlVal.Substring(et.Key.ToString().Length,
                        //                          xmlVal.Length - et.Key.ToString().Length - tempLastMate.Length) +
                        //         lastString;
                        xmlVal = xmlVal.Replace(":", "_-_");
                        xmlVal = xmlVal.Replace("&nbsp;", "");

                        if (!htKeyMate.GetKey(i).Equals("<script"))
                            sc.Add(xmlVal);
                        strInfo = strInfo.Remove(startIndex, endIndex + tempLastMate.Length - startIndex);
                    }
                }
            }
            finally
            {
                sr.Dispose();
                sr.Close();
            }
            if (File.Exists(strTestXmlPath))
                File.Delete(strTestXmlPath);
            StreamWriter sw = new StreamWriter(strTestXmlPath);
            try
            {
                sw.WriteLine("<root>");
                foreach (string str in sc)
                    sw.WriteLine(str);
                sw.WriteLine("</root>");
            }
            finally
            {
                sw.Dispose();
                sw.Close();
            }
            XmlDocument doc = new XmlDocument();
            doc.Load(strTestXmlPath);
            XmlNodeList nl = doc.SelectNodes("root/*");
            return nl;
        }

        public static void SetLanguageInfoXmlFile(StringCollection xmlFilePaths,string languageFilePath)
        {
            foreach (string str in xmlFilePaths)
                SetLanguageInfoXmlFile(str, languageFilePath);
        }

        private static string GetNodeAttrVal(XmlNode n ,string strAttrName)
        {
            if(n.Attributes[strAttrName]!=null)
            {
                string strVal = n.Attributes[strAttrName].Value;
                if (!string.IsNullOrEmpty(strVal))
                    return strVal;
            }
            return "";
        }

        private static void CopyNodeAttr(XmlNode srcNode,XmlNode tarNode,string strAttrName,XmlDocument doc)
        {
            string strAttrVal = GetNodeAttrVal(srcNode, strAttrName);
            if(strAttrVal.Length>0)
            {
                XmlAttribute attr = tarNode.Attributes[strAttrName] ?? doc.CreateAttribute(strAttrName);
                attr.Value = strAttrVal;
                tarNode.Attributes.Append(attr);
            }
        }

        private static XmlNode GetCtlSettingNode(XmlNode n,XmlDocument doc,XmlNode parentNode)
        {
            string strId = GetNodeAttrVal(n, "ID");
            XmlNode settingNode = null;
            if(strId.Length>0)
            {
                const string CTL_TYPE = "CtlType";
                settingNode = SetNode(parentNode, strId, doc);
                XmlAttribute attr = settingNode.Attributes[CTL_TYPE] ?? doc.CreateAttribute(CTL_TYPE);
                attr.Value = n.Name;
                settingNode.Attributes.Append(attr);
                CopyNodeAttr(n, settingNode, "Text", doc);
                CopyNodeAttr(n, settingNode, "Value", doc);
                CopyNodeAttr(n, settingNode, "ErrorMessage", doc);
                if (n.InnerText.Length > 0)
                    settingNode.InnerText = n.InnerText;
                if(n.Name == PgListKeyWord.Replace(":","_-_"))
                {
                    XmlNode columnsNode = n.SelectSingleNode("Columns");
                    if(columnsNode!=null && columnsNode.ChildNodes.Count>0)
                    {
                        int i = 1;
                        foreach(XmlNode tempNode in columnsNode.ChildNodes)
                        {
                            XmlNode pgNode = SetNode(settingNode, "Column_"+100000+i, doc);
                            XmlAttribute pgNodeAtt = pgNode.Attributes[CTL_TYPE] ?? doc.CreateAttribute(CTL_TYPE);
                            pgNodeAtt.Value = tempNode.Name;
                            pgNode.Attributes.Append(pgNodeAtt);
                            CopyNodeAttr(tempNode, pgNode, "DataField", doc);
                            CopyNodeAttr(tempNode, pgNode, "HeaderText", doc);
                            i++;
                        }
                    }
                }
            }
            return settingNode;
        }

        public static void SetLanguageInfoXmlFile(string xmlFilePath,string languageFilePath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            if (!File.Exists(languageFilePath))
            {
                XmlElement root = xmlDoc.CreateElement("Setting");
                xmlDoc.AppendChild(root);
                xmlDoc.Save(languageFilePath);
            }
            xmlDoc.Load(languageFilePath);

            XmlNode settingNode = xmlDoc.SelectSingleNode("Setting");
            XmlNode pageNode = SetNode(settingNode, "Page", xmlDoc);
            XmlNode userControlNode = SetNode(settingNode, "UserControl", xmlDoc);
            XmlNodeList nodeList = GetTempXmlNode(xmlFilePath);
            string nodeName = xmlFilePath.Replace(AppDomain.CurrentDomain.BaseDirectory, "").Replace("\\","_");
            XmlNode fileNode = null;
            string appName = "";
            if (xmlFilePath.LastIndexOf('.') > -1)
                appName = xmlFilePath.Substring(xmlFilePath.LastIndexOf('.') + 1);
            if (appName.ToLower().Equals("aspx"))
                fileNode = SetNode(pageNode, nodeName, xmlDoc);
            else if (appName.ToLower().Equals("ascx"))
                fileNode = SetNode(userControlNode, nodeName, xmlDoc);
            if(fileNode!=null)
            {
                if (nodeList != null && nodeList.Count > 0)
                {
                    foreach (XmlNode n in nodeList)
                    {
                        XmlNode tempNode = GetCtlSettingNode(n, xmlDoc, fileNode);
                        if (tempNode != null)
                            fileNode.AppendChild(tempNode);
                    }
                }
            }
            xmlDoc.Save(languageFilePath);
        }

        private static int csInfoItemAmount;

        private static void SetInfoByCsFile(string csFilePath, XmlDocument doc, NameObjectDictionary ndInfo)
        {
            if(File.Exists(csFilePath))
            {
                StreamReader sr = new StreamReader(csFilePath,Encoding.Default);
                try
                {
                    while(sr.Peek() > 0)
                    {
                        string rowInfo = sr.ReadLine();
                        if (rowInfo.Length > 0)
                        {
                            rowInfo = rowInfo.Trim();
                            if (rowInfo.StartsWith("///") || rowInfo.StartsWith("//") || rowInfo.StartsWith("<%"))
                                continue;
                            StringCollection scInfo = GetWordsIScn(rowInfo);
                            foreach (string strInfo in scInfo)
                            {
                                XmlNode childNode = null;
                                if (ndInfo.Contains(strInfo))
                                    childNode = ((XmlNode)ndInfo[strInfo]);
                                if (childNode == null)
                                {
                                    csInfoItemAmount = ndInfo.Count+1;
                                    childNode = doc.CreateElement("LanguageKeyWord_" + csInfoItemAmount.ToString().PadLeft(5, '0'));
                                    XmlAttribute attr = doc.CreateAttribute("Value");
                                    attr.Value = strInfo;
                                    childNode.Attributes.Append(attr);
                                    childNode.Attributes.Append(doc.CreateAttribute("Src"));
                                }
                                DirectoryInfo di = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);

                                if (di != null && di.Parent != null)
                                    di = di.Parent;
                                if (di == null) return;
                                string nodeName = csFilePath.Replace(di.FullName, "");
                                string strVal = childNode.Attributes["Src"].Value;
                                if (!strVal.StartsWith(nodeName + ";") && strVal.IndexOf("; " + nodeName + ";") < 0)
                                    childNode.Attributes["Src"].Value += nodeName + "; ";
                                ndInfo[strInfo] = childNode;
                            }
                        }
                    }
                }
                finally
                {
                    sr.Close();
                }
            }
        }

 
        public static StringCollection  GetWordsIScn(string words)
        {
            StringCollection scVal = new StringCollection();
            string TmmP;
            bool isCn = false;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < words.Length; i++)
            {
                TmmP = words.Substring(i, 1);
                byte[] sarr = System.Text.Encoding.GetEncoding("gb2312").GetBytes(TmmP);
                isCn = (sarr.Length == 2);
                if (isCn)
                    sb.Append(TmmP);
                if(sb.Length > 0 && isCn == false)
                {
                    scVal.Add(sb.ToString());
                    sb = new StringBuilder();
                    
                }
            }
            return scVal;
        }



        public static void SetLanguageInfoFile(XmlDocument xmlDoc,string csFilePath, string languageFilePath, NameObjectDictionary ndInfo)
        {
            if (ndInfo == null)
                ndInfo = new NameObjectDictionary();
            if (csFilePath.ToLower().EndsWith("designer.cs"))
                return;
            
            SetInfoByCsFile(csFilePath,xmlDoc,ndInfo);
            
            
        }

        private const string FILE_INFOS = "FileInfos";
        public static void SetLanguageInfoFile(StringCollection xmlFilePaths, string languageFilePath)
        {
            NameObjectDictionary ndInfo = new NameObjectDictionary();
            csInfoItemAmount = 0;
            XmlDocument xmlDoc = new XmlDocument();
            if (!File.Exists(languageFilePath))
            {
                XmlElement root = xmlDoc.CreateElement("Setting");
                xmlDoc.AppendChild(root);
                xmlDoc.Save(languageFilePath);
            }
            xmlDoc.Load(languageFilePath);
            XmlNode settingNode = xmlDoc.SelectSingleNode("Setting");
            XmlNode csNode = SetNode(settingNode, "FileInfos", xmlDoc);
            foreach (string str in xmlFilePaths)
                SetLanguageInfoFile(xmlDoc , str, languageFilePath,ndInfo);
            foreach (XmlNode n in ndInfo.Values)
                csNode.AppendChild(n);
            FileStream fs = new FileStream(languageFilePath, FileMode.OpenOrCreate);
            StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
            try
            {
                xmlDoc.Save(sw);
            }
            finally
            {
                sw.Close();
                fs.Close();
            }
            string strHKLangFilePath = languageFilePath.Replace("CN.xml", "HK.xml");
            if(File.Exists(strHKLangFilePath)) File.Delete(strHKLangFilePath);
            File.Copy(languageFilePath,strHKLangFilePath);
        }

        public static void GetDirAllFileNames(string dirPath, string[] strSeachKeys, StringCollection scFileNames)
        {
            foreach (string strSeachKey in strSeachKeys)
            {
                string[] files = Directory.GetFiles(dirPath, strSeachKey, SearchOption.AllDirectories);
                foreach (string str in files)
                {
                    string tempStr = str.ToLower();
                    if (tempStr.IndexOf("_svn") > 0 || tempStr.EndsWith("cn.xml") || tempStr.EndsWith("hk.xml") || tempStr.EndsWith("designer.cs"))
                        continue;
                    scFileNames.Add(str);
                }
            }
        }


        public NameValueCollection GetFileInfosFromLanguageSettingXml(string lanuageKey)
        {
            NameValueCollection ht = new NameValueCollection();
            XmlDocument doc = new XmlDocument();
            doc.Load(AppDomain.CurrentDomain.BaseDirectory + "Language\\" + lanuageKey + ".xml");
            XmlNodeList nl = doc.SelectNodes("/Setting/FileInfos/*");
            if (nl == null)
                return ht;
            //StringCollection scTemp = new StringCollection();
            foreach (XmlNode n in nl)
            {
                string strVal = GetNodeAttrVal(n, "Value");
                string strNodeName = n.Name;
                //if(!scTemp.Contains(strNodeName))
                //{
                //    scTemp.Add(strNodeName);
                    ht.Add(strNodeName, strVal);
                //}
            }
            return ht;
        }


        public void SetLanguageInfoForString(ref string strVal)
        {
            NameValueCollection ndTarget = GetFileInfosFromLanguageSettingXml(LanguageKey);
            foreach(string strKey in ndTarget.Keys)
            {
                if (strVal.IndexOf(strKey) > -1)
                {
                    string strNew = ndTarget[strKey];
                    strVal = strVal.Replace(strKey, strNew);
                }
            }
        }
    }
}
